package com.fanco.learn_datastruct_leetcode.juc;/**
 * @author qiaowang 2021/8/17
 */

import java.util.concurrent.TimeUnit;
import java.util.concurrent.atomic.AtomicReference;

/**
 * @author fanco
 * @Desc 自旋锁Demo
 * 通过循环比较获取知道成功为止，没有类似wait的阻塞
 *
 * 通过CAS 实现自旋锁  AA线程先进来 调用mylock方法 持有锁 5秒， 5秒后释放锁，BB 此时由于一直在通过 while循环自旋获取 锁，在AA线程释放锁后，
 * BB 立即就可以获取锁。
 */
public class SpinLockDemo {

    // 资源 原子引用线程
    AtomicReference<Thread> atomicReference = new AtomicReference<>();

    public static void main(String[] args) {
        SpinLockDemo spinLockDemo = new SpinLockDemo();

        // 线程A 持有 锁 5s
        new Thread(() -> {
            spinLockDemo.myLock();
            try {
                TimeUnit.SECONDS.sleep(5);
            } catch (Exception e) {
                e.printStackTrace();
            }
            spinLockDemo.myUnLock();

        }, "AA").start();

        // main线程停顿一秒，保证AA 在 BB 之前获取锁
        try {
            TimeUnit.SECONDS.sleep(1);
        } catch (Exception e) {
            e.printStackTrace();
        }

        // BB获取锁，由于此时AA在占用，BB进入mylock的while代码块中等待，重试，直到获取到lock
        new Thread(() -> {
            spinLockDemo.myLock();
            try {
                TimeUnit.SECONDS.sleep(1);
            } catch (Exception e) {
                e.printStackTrace();
            }
            spinLockDemo.myUnLock();
        }, "BB").start();
    }

    public void myLock() {
        // 当前线程
        Thread thread = Thread.currentThread();
        System.out.println(Thread.currentThread().getName() + "\t" + "come in");
        // 当前线程有值时， 则一直进行while循环
        while (!atomicReference.compareAndSet(null, thread)) { }
    }

    public void myUnLock() {
        Thread thread = Thread.currentThread();
        // 将原子引用数据 置为 null
        atomicReference.compareAndSet(thread, null);
        System.out.println(Thread.currentThread().getName() + "\t" + " unlock ...");
    }
}
